﻿/// <reference path="collisionPoint.js" />
/// <reference path="application.js" />


function Rope(x, y, angle) {
    this.targetedLength = 0;
    this.x = x;
    this.y = y;
    this.angle = angle;
    this.isHooked = false;
    this.anchorPoint = new CollisionPoint(x, y);
    this.ropePoints = new Array();
    this.vShoot = 25;
    this.strength = {
        x: 0,
        y: 0
    };
    

    if (typeof Rope.initialized == "undefined") {

        /// Activate tracking on an entity (the entity assumes it has x y fields)
        Rope.prototype.Think = function () {
            // Backup isHOoked value
            var isHookedOldValue = this.isHooked;

            if (!this.isHooked) {
                this.anchorPoint.Move(
                    Math.cos(this.angle * Math.PI / 180) * this.vShoot,
                    Math.sin(this.angle * Math.PI / 180) * this.vShoot);
            } else {
                this.Solve();
            }

            // Update hooked value
            this.isHooked = this.anchorPoint.isInCollision;

            if (this.isHooked && !isHookedOldValue) {
                // rope has just been hooked
                this.BuildRope();
            }
        };

        /// Stops the camera tracking
        Rope.prototype.Draw = function () {

            if (this.isHooked) {
                window.app.context.container2d.lineWidth = 5;
                window.app.context.container2d.strokeStyle = "#553C14";
                app.context.container2d.beginPath();
                window.app.context.container2d.moveTo(app.UI.ToScreenX(this.x), app.UI.ToScreenY(this.y));
                var alt = 0;
                for (var i in this.ropePoints) {
                    window.app.context.container2d.strokeStyle = alt >= 1 ? "#553C14" : "#754C24";
                    if (++alt > 2) {
                        alt = 0;
                    }
                    app.context.container2d.lineTo(app.UI.ToScreenX(this.ropePoints[i].x), app.UI.ToScreenY(this.ropePoints[i].y));
                    app.context.container2d.stroke();
                    app.context.container2d.beginPath();
                    window.app.context.container2d.moveTo(app.UI.ToScreenX(this.ropePoints[i].x), app.UI.ToScreenY(this.ropePoints[i].y));
                }

                window.app.context.container2d.strokeStyle = alt >= 1 ? "#553C14" : "#754C24";
                app.context.container2d.lineTo(app.UI.ToScreenX(this.anchorPoint.x), app.UI.ToScreenY(this.anchorPoint.y));
                app.context.container2d.stroke();
            } else {
                window.app.context.container2d.strokeStyle = "black";
                window.app.context.container2d.lineWidth = 1;
                window.app.context.container2d.beginPath();
                window.app.context.container2d.moveTo(app.UI.ToScreenX(this.x), app.UI.ToScreenY(this.y));
                window.app.context.container2d.lineTo(app.UI.ToScreenX(this.anchorPoint.x), app.UI.ToScreenY(this.anchorPoint.y));
                window.app.context.container2d.stroke();
            }

            this.anchorPoint.Draw();
        };

        /// Builds the rope
        Rope.prototype.BuildRope = function () {
            var radius = Math.sqrt(Math.pow(this.x - this.anchorPoint.x, 2) + Math.pow(this.y - this.anchorPoint.y, 2));
            this.targetedLength = radius;

            this.ropePoints = [];
            var finalAngle = Math.acos((this.anchorPoint.x - this.x) / radius);
            for (var i = app.context.ropeSettings.springBalancedLength; i < radius; i += app.context.ropeSettings.springBalancedLength) {
                var ropePoint = new CollisionPoint(
                    this.x + Math.cos(finalAngle) * i,
                    this.y + Math.sin(finalAngle) * i);
                ropePoint._vx = 0;
                ropePoint._vy = 0;
                this.ropePoints.push(ropePoint);
            }
        };

        /// Solves the rope dynamic
        Rope.prototype.Solve = function () {
            var massToApply = app.context.ropeSettings.weightUnitary / app.context.ropeSettings.springBalancedLength;

            for (var i in this.ropePoints) {

                // compute distance from neighbours
                var previousPoint = +i != 0 ? this.ropePoints[+i - 1] : this; // Has x,y coordinates for sure...
                var nextPoint = +i < this.ropePoints.length - 1 ? this.ropePoints[+i + 1] : this.anchorPoint; // Has x,y coordinates for sure...
                var dPrevious = Math.sqrt(Math.pow(this.ropePoints[i].x - previousPoint.x, 2) + Math.pow(this.ropePoints[i].y - previousPoint.y, 2));
                var dNext = Math.sqrt(Math.pow(this.ropePoints[i].x - nextPoint.x, 2) + Math.pow(this.ropePoints[i].y - nextPoint.y, 2));

                // Compute friction strength
                this.ropePoints[i]._frictionSx = -this.ropePoints[i]._vx * app.context.ropeSettings.frictionCoef;
                this.ropePoints[i]._frictionSy = -this.ropePoints[i]._vy * app.context.ropeSettings.frictionCoef;

                // Compute gravity strength
                this.ropePoints[i]._gravitySx = 0;
                this.ropePoints[i]._gravitySy = app.context.gravity * massToApply;

                // Compute springness strength
                this.ropePoints[i]._springnessP_Sx = app.context.ropeSettings.springness * (dPrevious - app.context.ropeSettings.springBalancedLength) * (previousPoint.x - this.ropePoints[i].x) / dPrevious;
                this.ropePoints[i]._springnessP_Sy = app.context.ropeSettings.springness * (dPrevious - app.context.ropeSettings.springBalancedLength) * (previousPoint.y - this.ropePoints[i].y) / dPrevious;
                this.ropePoints[i]._springnessN_Sx = app.context.ropeSettings.springness * (dNext - app.context.ropeSettings.springBalancedLength) * (nextPoint.x - this.ropePoints[i].x) / dNext;
                this.ropePoints[i]._springnessN_Sy = app.context.ropeSettings.springness * (dNext - app.context.ropeSettings.springBalancedLength) * (nextPoint.y - this.ropePoints[i].y) / dNext;

                // Submit strengths
                this.ropePoints[i]._vx += (this.ropePoints[i]._frictionSx + this.ropePoints[i]._gravitySx + this.ropePoints[i]._springnessP_Sx + this.ropePoints[i]._springnessN_Sx) / (massToApply * app.context.frameRate);
                this.ropePoints[i]._vy += (this.ropePoints[i]._frictionSy + this.ropePoints[i]._gravitySy + this.ropePoints[i]._springnessP_Sy + this.ropePoints[i]._springnessN_Sy) / (massToApply * app.context.frameRate);
            }

            for (var i in this.ropePoints) {
                // Move the collision point
                //this.ropePoints[i].Move(this.ropePoints[i]._vx, this.ropePoints[i]._vy);
                this.ropePoints[i].x += this.ropePoints[i]._vx;
                this.ropePoints[i].y += this.ropePoints[i]._vy;

                //If the rope point is in collision, reset velocity
                //                if (this.ropePoints[i].isInCollision) {
                //                    this.ropePoints[i]._vx = 0;
                //                    this.ropePoints[i]._vy = 0;
                //                }
            }
        };

        Rope.initialized = true;
    }
}